package com.hyzx.qbasic.admin.common.security;

import com.hyzx.qbasic.admin.model.constant.SessionKeyConst;
import com.hyzx.qbasic.admin.common.exception.IncorrectCaptchaException;
import com.hyzx.qbasic.admin.domain.service.IPermissionService;
import com.hyzx.qbasic.admin.model.dto.AdminUserInfo;
import com.hyzx.qbasic.admin.model.dto.AdminUserToken;
import com.hyzx.qbasic.admin.model.dto.AuthorizationInfo;
import com.hyzx.qbasic.admin.model.enums.LoginType;
import com.hyzx.qbasic.admin.model.enums.UserStatus;
import com.hyzx.qbasic.admin.model.po.UserLoginLogPO;
import com.hyzx.qbasic.admin.common.util.HttpContextUtils;
import com.hyzx.qbasic.admin.common.util.IpUtils;
import com.hyzx.qbasic.admin.common.util.PasswordEncryptor;
import com.hyzx.qbasic.admin.domain.service.IAdminUserService;
import com.hyzx.qbasic.admin.domain.service.ILogService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * Created by 黄江华 on 2017/9/7
 * Shiro身份验证和权限校验类
 */

@SuppressWarnings("Duplicates")
@Component
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private IAdminUserService userService;

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private ILogService logService;

    /**
     * 身份校验
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 验证码校验
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        String inputCaptcha = request.getParameter(SessionKeyConst.CAPTCHA_SESSION_KEY);
        String captcha = ShiroUtils.getCaptcha(SessionKeyConst.CAPTCHA_SESSION_KEY);

        if (!captcha.equalsIgnoreCase(inputCaptcha))
            throw new IncorrectCaptchaException();

        //校验用户是否存在
        String userName = String.valueOf(authenticationToken.getPrincipal());//用户名
        AdminUserToken adminUserToken = userService.getUserToken(userName);
        if (adminUserToken == null)
            throw new UnknownAccountException();

        //检查密码是否匹配
        String salt = userName + adminUserToken.getSalt();
        String password = new String((char[]) authenticationToken.getCredentials());
        String encryptedPassword = PasswordEncryptor.encrypt(password, salt);

        if (!adminUserToken.getPassword().equals(encryptedPassword))
            throw new IncorrectCredentialsException();

        //校验用户是否被锁定
        if (UserStatus.BLOCKED.equals(adminUserToken.getUserStatus()))
            throw new LockedAccountException();

        //用户信息写入会话
        AdminUserInfo adminUserInfo = userService.getUserInfo(adminUserToken.getUserId());
        ShiroUtils.setSessionAttribute(SessionKeyConst.USER_SESSION_KEY, adminUserInfo);

        //用户登录日志
        UserLoginLogPO loginLog = new UserLoginLogPO();
        loginLog.setUserId(adminUserToken.getUserId());
        loginLog.setUserName(adminUserToken.getUserName());
        loginLog.setLoginType(LoginType.ADMIN.ordinal());
        loginLog.setLoginTime(new Date());
        loginLog.setLoginIp(IpUtils.getIpAddress(request));
        logService.addUserLoginLog(loginLog);

        // 明文方式：需要自己做密码比对，显式调用Subject.login方法
        //return new SimpleAuthenticationInfo("admin","123456",getName());

        // 加密方式：使用Shiro的CredentialsMatcher进行密码匹配
        // 如果用户名和密码正确，则不会进入Controller的login方法，所以无法校验验证码
        return new SimpleAuthenticationInfo(userName,
                adminUserToken.getPassword(),
                ByteSource.Util.bytes(salt),//salt=username+salt
                getName());
    }

    /**
     * 权限校验
     */
    @Override
    protected org.apache.shiro.authz.AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        int userId = ShiroUtils.getCurrentUserId();
        AuthorizationInfo authorizationInfo = permissionService.getUserAuthorizationInfo(userId);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(authorizationInfo.getRoleList());
        simpleAuthorizationInfo.setStringPermissions(authorizationInfo.getPermissionList());

        return simpleAuthorizationInfo;
    }
}
